package xalan.smartgwt.record;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import xalan.xml.XMLUtils;

/**
 * Klasa odpowiedzialna za przesłanie odpowiedzi do klienta SmartGWT w wymaganym
 * formacie XML.
 * 
 * 
 * Format pliku XML został opisany w dokumentacji SmartGWT.
 * 
 * @author Xalan
 */
public class Response {
	public static final String DATA_ELEMENT = "data";
	public static final String STATUS_ELEMENT = "status";
	public static final String RESPONSE_ELEMENT = "response";
	
	private String status = "0";
	private List<Record> records = new LinkedList<Record>();
	
	public void addRecord(Record record) {
		this.records.add(record);
	}
	
	public List<Record> getRecords() {
		return records;
	}
	
	/**
	 * Metoda wysyła kolekcję obiektów jako rezultat żądania HTTP.
	 * 
	 * Kolekcja obiektów jest poddawana konwersji za pomocą obiektu konwertera.
	 * 
	 * @param <T>
	 * @param httpServletResponse odpowiedź dla klienta
	 * @param beans kolekcja obiektów
	 * @param converter obiekt odpowiedzialny za konwersję na typ Record
	 * @throws IOException
	 */
	public static <T> void sendBeans(
			HttpServletResponse httpServletResponse,
			Collection<T> beans,
			BeanToRecordConverter<T> converter) throws IOException
	{
		Response response = new Response();
		for(T o: beans) {
			Record record = new Record();
			converter.convert(record, o);
			response.addRecord(record);
		}
		response.send(httpServletResponse);
	}
	
	/**
	 * Wysyła obiekt Response jako rezultat żądania.
	 * 
	 * @param response odpowiedź dla klienta HTTP
	 * @throws IOException
	 */
	public void send(HttpServletResponse response) throws IOException {
		response.setContentType("text/xml");
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("pragma","no-cache");
		writeToOutputStream(response.getOutputStream());
	}

	/**
	 * Zapisuje obiekt Response to strumienia wyjściowego
	 * @param out strumień wyjściowy
	 */
	public void writeToOutputStream(OutputStream out) {
		try {
			XMLUtils.writeDocumentToOutputStream(
					this.serializeToXml(),
					out
			);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Dokonuje serializacji do dokumentu XML
	 * @return dokument XML
	 */
	public Document serializeToXml() {
		Document doc = null;
		try {
			doc = XMLUtils.newDocument();
			Element response = doc.createElement(RESPONSE_ELEMENT);
			doc.appendChild(response);
			
			Element status = doc.createElement(STATUS_ELEMENT);
			status.setTextContent(this.status);
			response.appendChild(status);
			
			Element data = doc.createElement(DATA_ELEMENT);
			response.appendChild(data);
			
			for(Record r : records) {
				Element record = r.serializeRecordToXML(doc);
				data.appendChild(record);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return doc;
	}

}
